package com.weilus.util.crypt;

import com.weilus.dto.ErrorResp;
import com.weilus.dto.RespEntity;
import com.weilus.util.encrypt.RSA;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.AnnotatedType;


@RestControllerAdvice
@ConfigurationProperties(prefix="http.rsa")
public class RestResponseAdvice implements ResponseBodyAdvice<Object> {
	
	private String privateKey;
	
	@ExceptionHandler(CryptException.class)
	public RespEntity encryptException(CryptException e) {
		return new ErrorResp(e.getCode(),e.getMsg());
	}
	
	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
		return !StringUtils.isEmpty(privateKey) &&
				(null != returnType.getMethodAnnotation(RsaEncrypt.class) ||
				existsAnnationInReturnType(returnType));
	}

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
		try {
			return RSA.encrypt(RSA.getPrivateKey(privateKey),body.toString().getBytes());
		} catch (Exception e) {
			throw new CryptException(CryptError.RSA_ENCRYPT_ERROR);
		}
	}
	
	private boolean existsAnnationInReturnType(MethodParameter returnType){
		AnnotatedType at = returnType.getMethod().getAnnotatedReturnType();
		if(null != at)return null != at.getAnnotation(RsaEncrypt.class);
		return false;
	}
}
